<template>
  <div>
    <div id="info">
      <h2>
        请确保你的浏览器支持 WebGL，可以点击
        <a href="https://get.webgl.org/" target="_blank">这里</a>
        进行检测。如果不支持，可百度处理方案。
      </h2>
      <span class="colorPicker">
        <input id="body-color" type="color" value="#ff0000" />
        <br />
        车身
      </span>
      <span class="colorPicker">
        <input id="details-color" type="color" value="#ffffff" />
        <br />
        轮毂
      </span>
      <span class="colorPicker">
        <input id="glass-color" type="color" value="#ffffff" />
        <br />
        玻璃
      </span>
    </div>

    <!-- 渲染汽车 -->
    <div id="container"></div>
  </div>
</template>
<script setup>
import { onMounted } from "vue";
// 1.导入 three.js
import * as THREE from "three";
// 导入GLTF模型加载器
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
// 导入DRACO解码器加载器
import { DRACOLoader } from "three/addons/loaders/DRACOLoader.js";
// 导入轨道控制器OrbitControls
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
// 导入HDR贴图加载器
import { RGBELoader } from "three/addons/loaders/RGBELoader.js";

// 定义相机、场景、渲染器对象
let camera, scene, renderer;

// 定义控制器对象
let controls;
let grid;
let wheels = [];

function init() {
  const container = document.getElementById("container");

  scene = new THREE.Scene();
  scene.background = new THREE.Color(0x333333);

  camera = new THREE.PerspectiveCamera(
    40,
    window.innerWidth / window.innerHeight,
    0.1,
    100
  );

  camera.position.set(4.25, 1.4, -4.5);

  // 创建WebGL渲染器对象，启用抗锯齿(更平滑)
  renderer = new THREE.WebGLRenderer({ antialias: true });
  // 设置渲染器的大小
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 设置渲染循环函数（代替 requestAnimationFrame 的替代函数）
  renderer.setAnimationLoop(render);
  // 将渲染器的画布元素添加到容器中
  container.appendChild(renderer.domElement);

  // 轨道
  controls = new OrbitControls(camera, container);
  // 启用阻尼效果
  controls.enableDamping = true;
  // 设置控制器能够缩放的最大距离
  controls.maxDistance = 9;
  // 设置控制器的焦点位置
  controls.target.set(0, 0.5, 0);
  // 更新控制器
  controls.update();

  // 环境贴图
  scene.environment = new RGBELoader().load(
    require("@/assets/venice_sunset_1k.hdr").default
  );
  scene.environment.mapping = THREE.EquirectangularReflectionMapping;

  // GridHelper
  grid = new THREE.GridHelper(20, 40, 0xffffff, 0xffffff);
  grid.material.opacity = 0.2;
  grid.material.depthWrite = false;
  grid.material.transparent = true;
  scene.add(grid);

  // 材质
  const bodyMeterial = new THREE.MeshPhysicalMaterial({
    color: 0xff0000,
    metalness: 1.0,
    roughness: 0.5,
    clearcoat: 1.0,
    clearcoatRoughness: 0.03,
    sheen: 0.5,
  });

  //修改色值
  document.getElementById("body-color").addEventListener("input", function () {
    bodyMeterial.color.set(this.value);
  });

  document
    .getElementById("details-color")
    .addEventListener("input", function () {
      detailsMaterial.color.set(this.value);
    });

  document.getElementById("glass-color").addEventListener("input", function () {
    glassMaterial.color.set(this.value);
  });

  // 创建细节材质对象，设置颜色和物理属性
  const detailsMaterial = new THREE.MeshStandardMaterial({
    color: 0xffffff,
    metalness: 1.0,
    roughness: 0.5,
  });

  // 创建玻璃材质对象，设置颜色和物理属性
  const glassMaterial = new THREE.MeshPhysicalMaterial({
    color: 0xffffff,
    metalness: 0.25,
    roughness: 0,
    transmission: 1.0,
  });

  // 阴影
  const shadow = new THREE.TextureLoader().load(
    require("@/assets/ferrari_ao.png")
  );

  // 2.3D加载
  const dracoLoader = new DRACOLoader();
  dracoLoader.setDecoderPath("decoder/");

  const loader = new GLTFLoader();
  loader.setDRACOLoader(dracoLoader);

  loader.load(require("@/assets/ferrari.glb").default, (gltf) => {
    const carModel = gltf.scene.children[0];
    carModel.getObjectByName("body").material = bodyMeterial;
    // rim_xx 参考 glb 文件配置
    // 设置前左轮辋的材质为细节材质
    carModel.getObjectByName("rim_fl").material = detailsMaterial;
    // 设置前右轮辋的材质为细节材质
    carModel.getObjectByName("rim_fr").material = detailsMaterial;
    // 设置后右轮辋的材质为细节材质
    carModel.getObjectByName("rim_rr").material = detailsMaterial;
    // 设置后左轮辋的材质为细节材质
    carModel.getObjectByName("rim_rl").material = detailsMaterial;
    // 设置车辆细节部分的材质为细节材质
    carModel.getObjectByName("trim").material = detailsMaterial;
    // 设置玻璃部分的材质为玻璃材质
    carModel.getObjectByName("glass").material = glassMaterial;

    // 获取车轮
    wheels.push(carModel.getObjectByName("wheel_fl"));
    wheels.push(carModel.getObjectByName("wheel_fr"));
    wheels.push(carModel.getObjectByName("wheel_rl"));
    wheels.push(carModel.getObjectByName("wheel_rr"));

    // 阴影配置
    const mesh = new THREE.Mesh(
      new THREE.PlaneGeometry(0.655 * 4, 1.3 * 4),
      new THREE.MeshBasicMaterial({
        map: shadow,
        blending: THREE.MultiplyBlending,
      })
    );
    mesh.rotation.x = -Math.PI / 2;
    mesh.renderOrder = 2;
    carModel.add(mesh);
    // 将车辆模型添加到场景中
    scene.add(carModel);
  });
}

function render() {
  controls.update();
  const time = performance.now() / 1000;
  grid.position.z = time % 1;

  wheels.forEach((wheel) => {
    wheel.rotation.x = -time * Math.PI * 2;
  });

  renderer.render(scene, camera);
}

onMounted(() => {
  init();
});
</script>
<style lang="scss">
body {
  color: #bbbbbb;
  background: #333333;
  text-align: center;
  overflow: hidden;
}

a {
  color: #08f;
}

.colorPicker {
  display: inline-block;
  margin: 0 10px;
}
</style>
